package br.uefs.dexa.rfframework.gui.interfaces;

import br.uefs.dexa.rfframework.gui.factory.GUIAbstractFactory;
import br.unicamp.ic.lis.rfframework.objects.DigitalObject;
import br.unicamp.ic.lis.rfframework.objects.DigitalObjectSet;
import br.unicamp.ic.lis.rfframework.objects.IDigitalObject;
import br.unicamp.ic.lis.rfframework.objects.LabeledDigitalObject;

public abstract class RFUserGUI implements RelevanceFeedbackViewer{
	
	public static final double MINIMUM_FREE_MEMORY_PERCENTAGE = 0.08; // * 100%
	
	
	private ObjectSetContainerPanel queryPatternPanel;
	
	private ObjectSetContainerPanel relevantObjectsPanel;
	
	private OutputObjectSetContainerPanel objectSetVisualizationPanel;
	
	private boolean queryPatternSelected = false;
	
	private boolean relevantObjectsSelected = false;
	
	
	
	public RFUserGUI () 
	{
		createPanels();
		compose();
	}
	
	private void createPanels () 
	{
		queryPatternPanel = GUIAbstractFactory.getInstance().getQueryPatternPanel(this);
		relevantObjectsPanel = GUIAbstractFactory.getInstance().getRelevantObjectsPanel(this);
		objectSetVisualizationPanel = GUIAbstractFactory.getInstance().getObjectSetVisualizationPanel(this);
	}
	
	
	public DigitalObjectSet<LabeledDigitalObject> indicationOfQueryPattern(DigitalObjectSet<DigitalObject> collection) 
	{
		objectSetVisualizationPanel.showObjects(collection);
		beforeQuerySelection();
		querySelectionMode();
		waitsForQuerySelection();
		afterQuerySelection();
		return queryPatternPanel.getObjects();
	}
	
	public boolean showSetOfObjects(DigitalObjectSet<DigitalObject> retrievedObjects) 
	{
		boolean satisfied;
		finalizeRFProgressViewer();
		objectSetVisualizationPanel.showObjects(retrievedObjects);
		satisfied = getUserSatisfaction();
		
		if(satisfied)
			finalize();
		
		return satisfied;		
	}
	
	public DigitalObjectSet<LabeledDigitalObject> userIndicationOfObjectsRelevance(DigitalObjectSet<DigitalObject> retrievedObjects,
			   																	   DigitalObjectSet<LabeledDigitalObject> queryPattern) { // obs: retrievedObjects and queryPattern not used here 

		DigitalObjectSet<LabeledDigitalObject> relevantObjects;
		beforeRelevanceFeedback();
		relevanceFeedbackMode();
		waitsForRelevanceFeedback();
		relevantObjects = relevantObjectsPanel.getObjects();
		afterRelevanceFeedback();
		return relevantObjects;
	}
	

	@Override
	public void beforeQuerySelection()
	{
		queryPatternPanel.beforeQuerySelection();
		relevantObjectsPanel.beforeQuerySelection();
		objectSetVisualizationPanel.beforeQuerySelection();
	}

	@Override
	public void querySelectionMode()
	{
		queryPatternPanel.querySelectionMode();
		relevantObjectsPanel.querySelectionMode();
		objectSetVisualizationPanel.querySelectionMode();
	}
	
	@Override
	public void afterQuerySelection()
	{
		queryPatternPanel.afterQuerySelection();
		relevantObjectsPanel.afterQuerySelection();
		objectSetVisualizationPanel.afterQuerySelection();
		
		startRFProgressViewer();
	}
	
	@Override
	public void beforeRelevanceFeedback()
	{
		queryPatternPanel.beforeRelevanceFeedback();
		relevantObjectsPanel.beforeRelevanceFeedback();
		objectSetVisualizationPanel.beforeRelevanceFeedback();
	}
	
	@Override
	public void relevanceFeedbackMode()
	{
		queryPatternPanel.relevanceFeedbackMode();
		relevantObjectsPanel.relevanceFeedbackMode();
		objectSetVisualizationPanel.relevanceFeedbackMode();
	}
	
	@Override
	public void afterRelevanceFeedback()
	{
		queryPatternPanel.afterRelevanceFeedback();
		relevantObjectsPanel.afterRelevanceFeedback();
		objectSetVisualizationPanel.afterRelevanceFeedback();
		
		startRFProgressViewer();
	}
	
	
	//Guarded block (see http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html)
	private synchronized void waitsForQuerySelection()
	{
		queryPatternSelected = false; 
		while(!queryPatternSelected) 
		{			
			try {
	            wait();
	        } catch (InterruptedException e) {}
		}
		queryPatternSelected = false; //reset for future new query
	}

	
	//Guarded block (see http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html)
	private synchronized void waitsForRelevanceFeedback()
	{
		relevantObjectsSelected = false; 
		while(!relevantObjectsSelected) 
		{
			try {
	            wait();
	        } catch (InterruptedException e) {}			
			
		}
		relevantObjectsSelected = false; //reset for future new iteration
	}
	
	
	public synchronized void queryPatternSelected()
	{
		queryPatternSelected = true;
		notifyAll();
	}
	
	public synchronized void relevantObjectsSelected()
	{
		relevantObjectsSelected = true;
		notifyAll();
	}
	
	public void addQueryObject(IDigitalObject object)
	{
		queryPatternPanel.addObject(object);
	}
	
	public void removeQueryObject(IDigitalObject object)
	{
		queryPatternPanel.removeObject(object);
		objectSetVisualizationPanel.resetSelected(object);	
	}
	
	public void addRelevantObject(IDigitalObject object)
	{
		relevantObjectsPanel.addObject(object);
	}
	
	public void removeRelevantObject(IDigitalObject object)
	{
		relevantObjectsPanel.removeObject(object);
		objectSetVisualizationPanel.resetSelected(object);
	}

	public ObjectSetContainerPanel getQueryPatternPanel() 
	{
		return queryPatternPanel;
	}

	public ObjectSetContainerPanel getRelevantObjectsPanel() 
	{
		return relevantObjectsPanel;
	}

	public OutputObjectSetContainerPanel getObjectSetVisualizationPanel() 
	{
		return objectSetVisualizationPanel;
	}
	
	
	
	
	/*
	 * Build GUI components and layout. 
	 * Must be implemented on subclasses.
	 */
	protected abstract void compose();
	
	
	/*
	 * Gets user satisfaction concerning retrieved result.
	 * As an example, can simply return a JOptionPane question dialog answer, or implement any arbitrarily complex mechanism.  
	 * Must be implemented on subclasses.
	 */
	protected abstract boolean getUserSatisfaction();
	
	
	
	/* 
	 * notifies GUI about user satisfaction.
	 * This is an auxiliary method created for assisting programmers on implementing the getUserSatisfaction() method mechanism.
	 * This method is usually called from one of the GUI internal panels to inform about user satisfaction.
	 * This method is empty, so it can optionally be implemented on subclasses.
	 */
	public synchronized void userSatisfaction(boolean value)
	{
		//empty
	}
	
	/*
	 * Start execution of some retrieval progress indicator for relevant objects processing.
	 * As an example, can implement a progress bar. 
	 * This method is empty, so it can optionally be implemented on subclasses.
	 */
	public void startRFProgressViewer()
	{
		//empty
	}
	
	/*
	 * Finalize execution of some retrieval progress indicator for relevant objects processing, 
	 * previously initiated on startRFProgressViewer() method.
	 * This method is empty, so it can optionally be implemented on subclasses.
	 */
	public void finalizeRFProgressViewer()
	{
		//empty
	}
	
	/*
	 * Finalize GUI after relevance feedback ends. 
	 * This method is empty, so it can optionally be implemented on subclasses.
	 */
	public void finalize()
	{
		//empty
	}
	
	
	
	

	
	
	
	
	
	
	
	

	
	
	
	
	
	
	
	

	
}
